importFiles(["/vueSystem/js/printTemplateUtil.js"]);

var SysPrintTemplateOrder = function () {
  var fn = {
    getStyle: function (option) {
      if (SysUtil.isEmpty(option)) {
        return {};
      }
      var style = {
        left: this.formatPx(option.x),
        top: this.formatPx(option.y),
        width: this.formatPx(option.width),
        height: this.formatPx(option.height),
        lineHeight: this.formatPx(option.lineHeight),
        textAlign: this.formatStyle(option.align),
        verticalAlign: this.formatStyle(option.verticalAlign),
        fontSize: this.formatPx(option.fontSize),
        padding: this.formatPx(option.padding),
        paddingLeft: this.formatPx(option.paddingLeft),
        paddingTop: this.formatPx(option.paddingTop),
        paddingRight: this.formatPx(option.paddingRight),
        paddingBottom: this.formatPx(option.paddingBottom)
      };

      if (option.hasBorder) {
        style.border = '1px solid #000';
      }

      var overflow = option.overflow;
      if (overflow !== undefined) {
        style.overflow = overflow;
      }

      return style;
    },
    getStyleStr: function (style) {
      var styleList = [];
      for (var key in style) {
        if (style[key] === undefined) {
          continue;
        }
        var property = key;
        var property = property.replace(/([A-Z])/g, "-$1").toLowerCase();
        var str = `${property}:${style[key]}`;
        styleList.push(str);
      }
      if (styleList.length === 0) {
        return '';
      }
      return styleList.join(';');
    },
    formatPx: function (size) {
      if (size === undefined) {
        return undefined;
      }
      if (typeof size === 'number') {
        size += 'px';
      }
      return size;
    },
    formatStyle: function (style) {
      if (!style) {
        return undefined;
      }
      return style;
    },
    getItemData: function (config, printData) {
      var dataType = config.dataType;
      var value = '';
      if (dataType === 'server') {
        value = _.get(printData, config.field, '');
      } else if (dataType === 'label') {
        value = config.label;
      } else if (dataType === 'function') {
        var params = this.getParams(config.params, printData);
        value = PrintTemplateUtil[config.functionName].apply(null, params);
      }
      return value;
    },
    getParams: function (paramConfigs, printData) {
      var reg = /^#{[.a-zA-Z\d]+}#$/;
      var params = _.map(paramConfigs, function (paramConfig) {
        var value;
        if (typeof paramConfig === 'string' && reg.test(paramConfig)) {
          var field = paramConfig.substring(2, paramConfig.length - 2);
          value = _.get(printData, field);
        } else {
          value = paramConfig;
        }
        if (value === undefined || value === null) {
          return '';
        }
        return value;
      });
      return params;
    },
    getItemHtml: function (config, printData) {
      var html = config.htmlText;
      var replaceStrs = html.match(/#{[.a-zA-Z\d]+}#/gi);
      if (replaceStrs !== null) {
        replaceStrs = _.uniq(replaceStrs);
        for (var i = 0; i < replaceStrs.length; i++) {
          var replaceStr = replaceStrs[i];
          var field = replaceStr.substring(2, replaceStr.length - 2);
          var value = _.get(printData, field, '');
          if (SysUtil.isEmpty(value)) {
            value = '';
          }

          html = html.replace(new RegExp(replaceStr, 'g'), value);
        }
      }

      var $html = $('<div></div>').html(html);
      var cotentStyle = config.cotentStyle;
      if (cotentStyle !== undefined) {
        $html.find('div,span').css(cotentStyle);
      }

      return $html.html();
    },
    getData: function (field, printData) {
      return _.get(printData, field);
    },
    getMomentFormat: function (format) {
      var format = format.replace(/y/g, 'Y').replace(/d/g, 'D');
      return format;
    }
  };

  var PrintTemplateMixin = {
    props: {
      option: {
        type: Object,
        required: true
      },
      printData: {
        type: Array,
        required: true
      },
      readOnly: {
        type: Boolean,
        default: false
      },
      printTemplate: Object,
      gridIndex: Number,
      templateId:String
    },
    data: function () {
      return {
        fn: fn
      };
    },
    methods: {
      getStyleStr(config) {
        var style = fn.getStyle(config);
        return fn.getStyleStr(style);
      },
      getComponentShow: function (data, printData) {
        var field = data.componentProp.showField;
        if (field === undefined) {
          return true;
        }

        var value = _.get(printData, field);
        if (SysUtil.isEmpty(value)) {
          return true;
        }
        return value;
      }
    }
  };

  /**
   * type为lineDiv 类型的模板组件
   */
  var PrintLineDivTemplate = function () {
    var template = /*html*/ `
      <div class="lineDiv" :style="fn.getStyle(option.config)" :contenteditable="option.config.edit">
        <span v-if="option.config.dataType==='html'" v-html="fn.getItemHtml(option.config,printData)"></span>
        <span v-else>
          {{fn.getItemData(option.config,printData)}}
        </span>
      </div>
    `;
    return {
      mixins: [PrintTemplateMixin],
      data: function () {
        return {};
      },
      template: template
    };
  }();

  /**
   * type为colDiv 类型的模板组件
   */
  var PrintColDivTemplate = function () {
    var template = /*html*/ `
      <div class="colDiv" :style="fn.getStyle(option.config)" :class="{'colDiv--border':option.hasAllBorder}">
        <div v-for="(data,index) in option.config.datas" :key="'div_'+gridIndex+'_'+index" class="order-data-item" 
          :style="fn.getStyle(data)">
          <div v-if="data.dataType==='html'" :contenteditable="data.edit" v-html="fn.getItemHtml(data,printData)"></div>
          <template v-else-if="data.dataType==='function'">
            <div class="clearfix colDiv-fun">
              <div v-if="data.htmlText" v-html="fn.getItemHtml(data,printData)"></div>
              <div :contenteditable="data.edit">{{fn.getItemData(data,printData)}}</div>
            </div>
          </template>
          <template v-else-if="data.dataType==='component'">
            <div :style="{width:data.componentWidth}">
              <template v-if="data.componentType==='datePicker'">
                <el-date-picker v-if="getComponentShow(data,printData)&&!readOnly" v-model="printData.tableHead[data.componentProp.field]" style="width:100%" type="date" 
                  size="mini" value-format="timestamp" :format="data.componentProp.format" :editable="false">
                </el-date-picker>
                <template v-else>
                  <span v-if="printData.tableHead[data.componentProp.field]!==null">
                    {{moment(printData.tableHead[data.componentProp.field]).format(fn.getMomentFormat(data.componentProp.format))}}
                  </span>
                </template>
              </template>
            </div>
          </template>
          <div v-else :contenteditable="data.edit">{{fn.getItemData(data,printData)}}</div>
        </div>
      </div>
    `;

    return {
      mixins: [PrintTemplateMixin],
      data: function () {
        return {};
      },
      template: template
    };
  }();

  /**
   * type为rowDiv 类型的模板组件
   */
  var PrintRowDivTemplate = function () {
    var template = /*html*/ `
      <div class="rowDiv" :style="fn.getStyle(option.config)" :class="{'rowDiv--border':option.hasAllBorder}">
        <div v-for="(data,index) in option.config.datas" :key="'div_'+gridIndex+'_'+index" class="order-data-item clearfix" 
          :style="fn.getStyle(data)">
          <div v-if="data.dataType==='html'" :contenteditable="data.edit" v-html="fn.getItemHtml(data,printData)" class="rowHtml clearfix"></div>
          <template v-else-if="data.dataType==='function'">
            <div v-html="fn.getItemHtml(data,printData)"></div>
            <div :contenteditable="data.edit">{{fn.getItemData(data,printData)}}</div>
          </template>
          <template v-else-if="data.dataType==='component'">
            <div v-html="fn.getItemHtml(data,printData)"></div>
            <div :style="{width:data.componentWidth}">
              <template v-if="data.componentType==='datePicker'">
                <el-date-picker v-if="getComponentShow(data,printData)&&!readOnly" v-model="printData.tableHead[data.componentProp.field]" style="width:100%" type="date" 
                  size="mini" value-format="timestamp" :format="data.componentProp.format" :editable="false">
                </el-date-picker>
                <template v-else>
                  <span v-if="printData.tableHead[data.componentProp.field]!==null">
                    {{moment(printData.tableHead[data.componentProp.field]).format(fn.getMomentFormat(data.componentProp.format))}}
                  </span>
                </template>
              </template>
            </div>
          </template>
          <template v-else>
            <div v-if="!data.htmlText" :style="{width:data.labelWidth?data.labelWidth+'px':undefined}">{{data.inputLabel}}</div>
            <div v-else v-html="fn.getItemHtml(data,printData)"></div>
            <div :contenteditable="data.edit">{{fn.getItemData(data,printData)}}</div>
          </template>
        </div>
      </div>
    `;

    return {
      mixins: [PrintTemplateMixin],
      data: function () {
        return {
          moment: moment
        };
      },
      template: template
    };
  }();

  /**
   * type为table 类型的模板组件
   */
  var PrintTableTemplate = function () {
    var template = /*html*/ `
      <div class="table" :style="fn.getStyle(option.config)">
        <table cellspacing="0" cellpadding="0" class="print-template-table">
          <colgroup>
            <col v-for="(colWidth,index) in option.config.colWidths" :key="'col_'+index" :width="colWidth+'px'">
          </colgroup>
          <thead>
            <tr v-for="(prefixOption,rowIndex) in prefixOptions" :key="'prefixRow_'+rowIndex" :style="{height:prefixOption.height}">
              <td v-for="(option,colIndex) in prefixOption.cols" :key="'prefixCol_'+rowIndex+'_'+colIndex" :rowspan="getTableSpan(option.rowspan)" 
                :colspan="getTableSpan(option.colspan)" :style="option.style">
                <div v-if="option.dataType==='html'" v-html="fn.getItemHtml(option,printData)"></div>
              </td>
            </tr>
            <tr v-for="(heads,rowIndex) in option.config.tableHeader" :key="'headRow_'+rowIndex" :style="{height:option.config.colHeight+'px'}">
              <td v-for="(head,colIndex) in heads" :key="'headCell_'+rowIndex+'_'+colIndex" :style="fn.getStyle(head)">
                {{head.label}}
              </td>
            </tr>
          </thead>
          <tbody>
            <tr v-for="(data,rowIndex) in tableData" :key="'bodyRow_'+data.tableDataId" :style="{height:option.config.colHeight+'px'}">
              <td v-for="(body,colIndex) in option.config.tableBody" v-if="hasMergeShow(data,body)" :key="'bodyCell_'+data.tableDataId+'_'+colIndex" 
                :rowspan="getTableRowSpan(data,body)" :style="fn.getStyle(body.config)" :contenteditable="body.edit">
                {{getTableCellData(data,body,rowIndex,colIndex)}}
              </td>
            </tr>
            <tr v-for="fillRow in fillRows" :key="'fillRow_'+fillRow" :style="{height:option.config.colHeight+'px'}">
              <td v-for="(body,fillCol) in option.config.tableBody" :key="'fillRow_'+fillRow+'_'+fillCol"></td>
            </tr>
            <tr v-if="option.config.tableStat" class="tableStat">
              <template v-for="(stat,index) in option.config.tableStat">
                <td v-if="stat===null" :key="'stat_'+index"></td>
                <td v-else :key="'stat_'+index" :colspan="stat.span?stat.span:1" :style="getTableStatStyleStr(stat.config,option.config)">
                  <span v-if="stat.config.label!==undefined">{{stat.config.label}}</span>
                  <span>{{getTableStatData(stat.config)}}</span>
                </td>
              </template>
            </tr>
          </tbody>
        </table>
      </div>
    `;

    return {
      mixins: [PrintTemplateMixin],
      data: function () {
        var option = this.option;
        return {
          fillRows: 0,
          tableData: [],
          statId:'',
          prefixOptions: this.getPrefixOption(option)
        };
      },
      watch: {
        printData: {
          immediate: true,
          handler: function () {
            this.resetFillTable();
          }
        },
        option: function () {
          this.resetFillTable();
        }
      },
      methods: {
        resetFillTable: function () {
          this.fillRows = 0;
          var self = this;
          this.tableData = this.getTableData(this.option);
          self.$nextTick(function () {
            self.fillTable();
            self.$nextTick(function () {
              self.fillHeight();
            });
          });
        },
        fillTable: function () {
          var option = this.option;
          if (!option.fillRow) {
            return;
          }
          var colHeight = _.get(option, 'config.colHeight');
          if (colHeight === undefined) {
            this.fillRows = 0;
          }

          var $table = $(this.$el);
          var tableDivHeight = $table.height();
          var tableHeight = $table.find('.print-template-table').height();
          if (tableDivHeight > tableHeight) {
            this.fillRows = Math.floor((tableDivHeight - tableHeight) / colHeight);
          } else {
            this.fillRows = 0;
          }
        },
        fillHeight: function () {
          var option = this.option;
          if (!option.fillHeight) {
            return;
          }

          var $table = $(this.$el);
          var tableDivHeight = $table.height();
          var tableHeight = $table.find('.print-template-table').height();
          if (tableDivHeight <= tableHeight) {
            return;
          }

          var rangeHeight = tableDivHeight - tableHeight;
          var $rows = $table.find('.print-template-table tbody tr:not(.tableStat)');
          var len = $rows.length;
          var addHeight = Math.floor(rangeHeight / len);
          var surplusHeight = rangeHeight % len;
          for (var i = 0; i < len; i++) {
            var $row = $($rows[i]);
            var rowHeight = $row.height();
            var addRowHeight = addHeight;
            if (surplusHeight > 0) {
              addRowHeight++;
              surplusHeight--;
            }
            rowHeight += addRowHeight;
            $row.height(rowHeight);
          }
        },
        getTableData: function (option) {
          var printData = this.printData;
          var tableField = _.get(option, 'config.tableField');
          var data = _.get(printData, tableField);
          data = _.cloneDeep(data);
          if (!_.isArray(data)) {
            data = [];
          }
          if (data.length === 0) {
            return [];
          }

          var orderRul = option.orderRul;
          if (orderRul !== undefined) {
            data = this.orderTableData(data, orderRul);
          }

          var mergeRul = option.mergeRul;
          if (mergeRul !== undefined) {
            this.mergeTableData(data, option);
          }
          for (var i = 0; i < data.length; i++) {
            var d = data[i];
            d.tableDataId = SysUtil.getId();
          }
          return data;
        },
        orderTableData: function (data, orderRul) {
          var orderField = [];
          var orderType = [];
          for (var i = 0; i < orderRul.length; i++) {
            var rul = orderRul[i];
            var arr = rul.split('-');
            orderField.push(arr[0]);
            var rulType = arr[1];
            if (SysUtil.isEmpty(rulType)) {
              rulType = 'asc';
            }
            orderType.push(rulType);
          }
          data = _.orderBy(data, orderField, orderType);
          return data;
        },
        mergeTableData: function (data, option) {
          var mergeRul = option.mergeRul;
          for (var key in mergeRul) {
            var ruls = mergeRul[key];
            for (var i = 0; i < data.length;) {
              var currentData = data[i];
              var span = this.getSameTableDataNum(data, i, ruls, key);
              span++;
              _.set(currentData, `megerRul.${key}`, span);
              i += span;
            }
          }
        },
        getSameTableDataNum: function (data, index, ruls, key) {
          var currentData = data[index];
          index++;
          var nextData;
          var num = 0;
          while (true) {
            nextData = data[index];
            if (nextData === undefined) {
              break;
            }
            var flag = true;
            for (var i = 0; i < ruls.length; i++) {
              var rul = ruls[i];
              if (currentData[rul] !== nextData[rul]) {
                flag = false;
                break;
              }
            }
            if (!flag) {
              break;
            }
            _.set(nextData, `megerRul.${key}`, 0);
            num++;
            index++;
          }
          return num;
        },
        getTableCellData: function (data, config, rowIndex) {
          var colType = config.colType;
          if (colType === 'lineNo') {
            return rowIndex + 1;
          } else if (colType === 'function') {
            return this.getFunData(data, config, rowIndex);
          }

          var field = config.field;
          if (SysUtil.isEmpty(field)) {
            return '';
          }
          var value;
          if (field !== undefined) {
            value = _.get(data, field);
          }
          return value;
        },
        getFunData: function (data, config, rowIndex) {
          var functionName = config.functionName;
          if (functionName === undefined) {
            return '';
          }
          var params = config.params;
          var paramData = fn.getParams(params, data);

          var otherParams = config.otherParams;
          if (otherParams !== undefined) {
            var paramConfig = {
              tableData: this.tableData,
              rowIndex: rowIndex,
              data: data,
              config: config
            };
            for (var i = 0; i < otherParams.length; i++) {
              var otherParam = otherParams[i];
              var param = paramConfig[otherParam];
              if (param !== undefined) {
                paramData.push(param);
              }
            }
          }
          var value = PrintTemplateUtil[functionName].apply(null, paramData);
          if (SysUtil.isEmpty(value)) {
            return '';
          }
          return value;
        },
        getTableStatData: function (config) {
          var funName = config.funName;
          if (funName === undefined) {
            return '';
          }
          var tableData = this.tableData;
          var value = '';
          if (funName !== undefined) {
            var fun = funName.split('-');
            var params = fun[1];
            if (params === undefined) {
              params = [];
            } else {
              params = params.split(',');
            }

            params.unshift(tableData);
            value = PrintTemplateUtil[fun[0]].apply(null, params);
          }
          return value;
        },
        getPrefixOption: function (option) {
          var prefixAreas = option.config.prefixArea;
          if (prefixAreas === undefined) {
            return [];
          }
          var prefixOptions = [];
          for (var i = 0; i < prefixAreas.length; i++) {
            var prefixArea = prefixAreas[i];
            prefixArea = _.cloneDeep(prefixArea);
            var style = fn.getStyle(prefixArea);
            prefixArea.style = fn.getStyleStr(style);

            var cols = prefixArea.cols;
            for (var j = 0; j < cols.length; j++) {
              var col = cols[j];
              var style = fn.getStyle(col);
              col.style = fn.getStyleStr(style);
              var rowspan = col.rowspan;
              col.rowspan = rowspan ? rowspan : 1;
              var colspan = col.colspan;
              col.colspan = colspan ? colspan : 1;
            }
            prefixOptions.push(prefixArea);
          }
          return prefixOptions;
        },
        getTableStatStyleStr: function (statConfig, optionConfig) {
          var style = fn.getStyle(statConfig);
          var colHeight = optionConfig.colHeight;
          style.height = colHeight + 'px';
          return fn.getStyleStr(style);
        },
        hasMergeShow: function (data, body) {
          var mergeRulName = body.mergeRulName;
          if (mergeRulName === undefined) {
            return true;
          }

          var megerRul = data.megerRul;
          if (megerRul === undefined) {
            return true;
          }

          var rul = megerRul[mergeRulName];
          if (rul === undefined) {
            return true;
          }
          return rul !== 0;
        },
        getTableRowSpan: function (data, body) {
          var mergeRulName = body.mergeRulName;
          if (mergeRulName === undefined) {
            return 1;
          }

          var megerRul = data.megerRul;
          if (megerRul === undefined) {
            return 1;
          }

          var rul = megerRul[mergeRulName];
          if (rul === undefined) {
            return 1;
          }
          return rul;
        },
        getTableSpan: function (span) {
          if (span === undefined) {
            return 1;
          }
          if (typeof span === 'number') {
            return span;
          }

          var type = span.type;
          var printData = this.printData;
          if (type === 'function') {
            var params = span.params;
            params = fn.getParams(params, printData);
            var functionName = span.funName;
            return PrintTemplateUtil[functionName].apply(null, params);
          }
        }
      },
      template: template
    };
  }();

  var template = /*html*/ `
    <div class="sys-print-template-order">
      <div class="print-area print-template-order">
        <div :style="getPageSize()" class="page-content">
          <div v-for="(option,index) in options" :key="'div_'+templateId+'_'+index" :style="fn.getStyle(option)" class="order-item"
            :class="'order-item-'+option.type">
            <print-line-div-template v-if="option.type==='lineDiv'" :option="option" :print-data="printData" :print-status="printStatus" :grid-index="index"
              :read-only="readOnly" :print-template="printTemplate" :template-id="templateId">
            </print-line-div-template>
            <print-col-div-template v-else-if="option.type==='colDiv'" :option="option" :print-data="printData" :print-status="printStatus" :grid-index="index"
              :read-only="readOnly" :print-template="printTemplate" :template-id="templateId">
            </print-col-div-template>
            <print-row-div-template v-else-if="option.type==='rowDiv'" :option="option" :print-data="printData" :print-status="printStatus" :grid-index="index"
              :read-only="readOnly" :print-template="printTemplate" :template-id="templateId">
            </print-row-div-template>
            <print-table-template v-else-if="option.type==='table'" :option="option" :print-data="printData" :print-status="printStatus" :grid-index="index"
              :read-only="readOnly" :print-template="printTemplate" :template-id="templateId">
            </print-table-template>
          </div>
        </div>
      </div>
    </div>
  `;

  return {
    props: {
      printData: {
        type: Array,
        required: true
      },
      printTemplate: {
        type: Object,
        required: true
      },
      readOnly: {
        type: Boolean,
        default: false
      }
    },
    watch: {
      printTemplate: function () {
        var printTemplate = this.printTemplate;
        this.options = printTemplate.options;
        this.templateId = SysUtil.getId();
      }
    },
    data: function () {
      var printTemplate = this.printTemplate;
      return {
        options: printTemplate.options,
        fn: fn,
        printStatus: false,
        templateId: SysUtil.getId()
      };
    },
    methods: {
      getPageSize: function () {
        var printTemplate = this.printTemplate;
        var size = printTemplate.size;
        size = size.split('*');
        return {
          width: `${Number(size[0])-20}px`,
          height: `${Number(size[1])-20}px`
        };
      },
      print: function () {
        var $print = $(this.$el).find('.print-area');
        $print = $print.clone();
        $print.css('display', 'none');
        $('#app').append($print);
        window.print();
        $print.remove();
      }
    },
    components: {
      PrintLineDivTemplate: PrintLineDivTemplate,
      PrintColDivTemplate: PrintColDivTemplate,
      PrintRowDivTemplate: PrintRowDivTemplate,
      PrintTableTemplate: PrintTableTemplate
    },
    template: template
  };
}();